package com.cq.hd.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cq.hd.common.constant.Constant;
import com.cq.hd.common.constant.RedisKeyConstant;
import com.cq.hd.common.entity.UserInfo;
import com.cq.hd.common.enums.ResponseEnums;
import com.cq.hd.common.enums.biz.DeleteStatusEnum;
import com.cq.hd.common.response.ResultGenerator;
import com.cq.hd.common.utils.JwtUtil;
import com.cq.hd.common.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Mono;

import java.util.concurrent.TimeUnit;

/**
 * @description: app用户
 * @author: mYunYu
 * @date: 2021/7/7 17:17
 * @version: v1.0
 */
@Slf4j
public class UserJwtCheckGatewayFilterFactory extends AbstractGatewayFilterFactory<UserJwtCheckGatewayFilterFactory.Config> {

    public UserJwtCheckGatewayFilterFactory() {
        super(UserJwtCheckGatewayFilterFactory.Config.class);
    }

    public static class Config {

    }

    private RedisUtil redisUtil;

    @Autowired
    public void setRedisUtil(RedisUtil redisUtil) {
        this.redisUtil = redisUtil;
    }

    /**
     * @Description: 用户认证
     * @Param: [config]
     * @Return: org.springframework.cloud.gateway.filter.GatewayFilter
     * @Auther: mYunYu
     * @Date: 2021/8/19 14:54
     */
    @Override
    public GatewayFilter apply(Config config) {
        return ((exchange, chain) -> {
            // 响应未登录的异常
            ServerHttpResponse response = exchange.getResponse();
            // 设置headers
            HttpHeaders httpHeaders = response.getHeaders();
            httpHeaders.add("Content-Type", "application/json; charset=UTF-8");
            httpHeaders.add("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");

            // 获取请求头中的token
            String token = exchange.getRequest().getHeaders().getFirst("Authorization");
            // 判断token是否为空
            if (StringUtils.isEmpty(token)) {
                log.warn("Headers未设置token");
                String warningStr = JSON.toJSONString(ResultGenerator.error(ResponseEnums.USER_ACCESS_DENIED));
                DataBuffer bodyDataBuffer = response.bufferFactory().wrap(warningStr.getBytes());
                return response.writeWith(Mono.just(bodyDataBuffer));
            }

            // 获取保存在token中的userId
            String userId = JwtUtil.getAudience(token, 0);
            String lookupLogKey = userId;
            try {
                lookupLogKey = JwtUtil.getAudience(token, 1);
            } catch (Exception ignored) {
            }
            // 获取Redis缓存中的用户登录密钥
            String loginKey = redisUtil.get(String.format(RedisKeyConstant.USER_LOGIN_KEY, lookupLogKey));
            if (com.cq.hd.common.utils.StringUtils.isNullOrEmpty(loginKey)) {
                log.warn("登录失效:UserJwtCheckGatewayFilterFactory.checkLogin");
                String warningStr = JSON.toJSONString(ResultGenerator.error(ResponseEnums.USER_ACCESS_DENIED));
                DataBuffer bodyDataBuffer = response.bufferFactory().wrap(warningStr.getBytes());
                return response.writeWith(Mono.just(bodyDataBuffer));
            }

            // Token验证
            boolean flag = JwtUtil.tokenVerify(token, loginKey);
            if (!flag) {
                log.warn("Token验证失败:UserJwtCheckGatewayFilterFactory.checkLogin");
                String warningStr = JSON.toJSONString(ResultGenerator.error(ResponseEnums.USER_ACCESS_DENIED));
                DataBuffer bodyDataBuffer = response.bufferFactory().wrap(warningStr.getBytes());
                return response.writeWith(Mono.just(bodyDataBuffer));
            }

            // 获取Redis缓存中的用户信息
            String userInfoRedis = redisUtil.get(String.format(RedisKeyConstant.USER_INFO_KEY, userId));
            // 转换为实体类
            UserInfo userInfo = JSONObject.parseObject(userInfoRedis, UserInfo.class);
            // 判断用户是否存在
            if (userInfo == null) {
                log.warn("用户不存在:UserJwtCheckGatewayFilterFactory.checkLogin");
                String warningStr = JSON.toJSONString(ResultGenerator.error(ResponseEnums.USER_ACCESS_DENIED));
                DataBuffer bodyDataBuffer = response.bufferFactory().wrap(warningStr.getBytes());
                return response.writeWith(Mono.just(bodyDataBuffer));
            } else {
                // 判断用户是否被封禁
                if (userInfo.getState() == 2) {
                    String warningStr = JSON.toJSONString(ResultGenerator.error(ResponseEnums.USER_NOT_FOUND));
                    DataBuffer bodyDataBuffer = response.bufferFactory().wrap(warningStr.getBytes());
                    return response.writeWith(Mono.just(bodyDataBuffer));
                }
            }

            // 重新设置登录失效时间
            redisUtil.expire(String.format(RedisKeyConstant.USER_LOGIN_KEY, userId), Constant.USER_LOGIN_TIMEOUT, TimeUnit.SECONDS);
            return chain.filter(exchange);
        });
    }

}